package com.ciaojian.worker.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ciaojian.core.constant.RedisConstant;
import com.ciaojian.core.enums.business.CheckUserClockTypeEnum;
import com.ciaojian.core.enums.business.WorkerWorkerStatusEnum;
import com.ciaojian.core.mapper.CheckUserMapper;
import com.ciaojian.core.model.Roster;
import com.ciaojian.core.model.Scheduling;
import com.ciaojian.core.model.vo.*;
import com.ciaojian.core.service.CheckUserService;
import com.ciaojian.core.util.LogUtil;
import com.ciaojian.core.util.TimeUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author Atlakyn
 */
@Service
public class CheckUserServiceImpl extends CheckUserService<CheckUserMapper, CheckUser> {
    @Resource
    private SchedulingServiceImpl schedulingService;
    @Resource
    private WorkerServiceImpl workerService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private CheckUserMapper checkUserMapper;

    /**
     * 上班打卡
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean punchIn(CheckUser checkUser) {
        // 获取当日班次
        Scheduling scheduling = schedulingService.getWorkerScheduledToday(checkUser.getUserId());
        Assert.notNull(scheduling, "当天没有排班");
        try {

            Roster roster = new Roster().selectById(scheduling.getRosterId());
            // 判断是否已到最早打卡时间
            Assert.isTrue(TimeUtil.compareTo(checkUser.getCurDate(), roster.getEarlyTime()) >= 0, "未到打卡时间");
            // 判断是否已过班次中点
            Assert.isTrue(TimeUtil.compareTo(checkUser.getCurDate(), roster.getMiddleTime()) <= 0, "已过打卡时间");

            // 打卡统计
            Integer count = this.lambdaQuery()
                    .eq(CheckUser::getUserId, checkUser.getUserId())
                    .eq(CheckUser::getDate, checkUser.getDate())
                    .eq(CheckUser::getType, "上班打卡")
                    .count();
            Assert.isTrue(count == 0, "您已打上班卡");

            // 打卡记录
            redisTemplate.opsForList().leftPush(RedisConstant.CLOCK_IN + checkUser.getStoreId(), checkUser);
            redisTemplate.expireAt(RedisConstant.CLOCK_IN + checkUser.getStoreId(), DateUtil.tomorrow());
            // 设置就餐时间
//            schedulingService.setupDinnerTime(checkUser.getUserId());

            // 迟到
            if (TimeUtil.compareTo(checkUser.getCurDate(), roster.getStartWorkTime()) > 0) {
                checkUser.setClockType(CheckUserClockTypeEnum.LATE);
            }


            // 修改发型师状态为上班
            workerService.updateWorkerStatus(checkUser.getUserId(), WorkerWorkerStatusEnum.WORKING);

            // 新增打卡记录
            return checkUser.insert();
        } catch (ParseException e) {
            e.printStackTrace();
            LogUtil.writeErrorLog(e.getMessage());
            return false;
        }
    }

    /**
     * 下班打卡
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean punchOff(CheckUser checkUser) {
        // 获取当日班次
        Scheduling scheduling = schedulingService.getWorkerScheduledToday(checkUser.getUserId());
        Assert.notNull(scheduling, "当天没有排班");
        try {
            Date curDate = new SimpleDateFormat("HH:mm:ss").parse(checkUser.getTime());
            Roster roster = new Roster().selectById(scheduling.getRosterId());
            // 判断是否已过最晚打卡时间
            Assert.isTrue(TimeUtil.compareToDown(curDate, roster.getLastTime()) <= 0, "已过打卡时间");

            // 是否打过卡
            LambdaQueryWrapper<CheckUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(CheckUser::getUserId, checkUser.getUserId())
                    .eq(CheckUser::getDate, checkUser.getDate())
                    .eq(CheckUser::getType, "下班打卡");

            // 早退
            if (TimeUtil.compareToDown(curDate, roster.getEndWorkTime()) < 0) {
                checkUser.setClockType(CheckUserClockTypeEnum.LEAVE_EARLY);
            }

            // 修改发型师状态为下班
            workerService.updateWorkerStatus(checkUser.getUserId(), WorkerWorkerStatusEnum.DOWNTIME);

            // 不为空则更新打卡记录
            CheckUser one = this.getOne(lambdaQueryWrapper);
            if (one != null) {
                BeanUtil.copyProperties(checkUser, one, CopyOptions.create().setIgnoreNullValue(true));
                return one.updateById();
            }


            // 新增打卡记录
            return checkUser.insert();
        } catch (ParseException e) {
            e.printStackTrace();
            LogUtil.writeErrorLog(e.getMessage());
            return false;
        }
    }



    public List<ClockMonthVo> myClockMonth(int workerId, String month){
        //查询打卡表
        List<ClockMonthVo> clockMonthVos = checkUserMapper.myClockMonth(workerId, month);
        for (ClockMonthVo clockMonthVo : clockMonthVos) {
            // 上班 0为正常  下班1为正常
            // 上下班统一vo  0为正常  1为异常
            try {
                if (clockMonthVo.getClockOn() != 0 || clockMonthVo.getClockOff() != 1) {
                    clockMonthVo.setClockStatus(1);
                }else {
                    clockMonthVo.setClockStatus(0);
                }
            }catch (Exception e){

            }
        }
        return clockMonthVos;
    }

    public ClockDayVo myClockDay(int workerId, String day) throws ParseException {
        //时间运算
        SimpleDateFormat dayf = new SimpleDateFormat("yyyy-MM-dd");
        Date dayDate = dayf.parse(day);
        Date dateNow = new Date();

        //拿到今天年月日
        String nowformat = dayf.format(dateNow);
        dateNow = dayf.parse(nowformat);


        ClockDayVo clockDayVo = checkUserMapper.myClockDay(workerId,day);
        if (ObjectUtil.isNull(clockDayVo)){
            ClockDayVo clockDayVo1 = new ClockDayVo();
            clockDayVo1.setWorkerText("无打卡记录");
            return clockDayVo1;
        }

        //正常上班考勤
        if(clockDayVo.getStatus()==0){
            Date timeOff = clockDayVo.getTimeOff();
            Date timeOn = clockDayVo.getTimeOn();
            SimpleDateFormat f = new SimpleDateFormat("HH:mm:ss");

            //有打卡
            if (ObjectUtil.isNotNull(timeOn)){
                 clockDayVo.setTimeUp(f.format(timeOn));
            }else {  //无打卡
                //判断是否今日
                if (dayDate.getTime()>=dateNow.getTime()){
                    clockDayVo.setTimeDown("未打卡");
                }else {
                    //为空给前端,判断为缺卡
                    clockDayVo.setTimeUp(null);
                }
            }

            //有打卡
            if (ObjectUtil.isNotNull(timeOff)) {
                clockDayVo.setTimeDown(f.format(timeOff));
            }else { //无打卡
                //判断是否今日
                if (dayDate.getTime()>=dateNow.getTime()){
                    clockDayVo.setTimeDown("未打卡");
                }else {
                    //为空给前端,判断为缺卡
                    clockDayVo.setTimeDown(null);
                }
            }

            if (ObjectUtil.isNotNull(timeOff)&&ObjectUtil.isNotNull(timeOn)) {
                long sub = Math.abs(timeOff.getTime() - timeOn.getTime());
                clockDayVo.setWorkerText("工作时长"+sub/1000/60/60+"小时");
            }

        }else if (clockDayVo.getStatus()==1){
            clockDayVo.setWorkerText("调休");
        }else if (clockDayVo.getStatus()==2){
            clockDayVo.setWorkerText("请假");
        }

        return clockDayVo;
    }


    public ClockStatisticsVo myClockStatistics(int workerId, String month){
        ClockStatisticsVo clockStatisticsVo = new ClockStatisticsVo();

        List<ClockDayVo> clockDayVos = checkUserMapper.myClockDayTime(workerId,month);

        //出勤天数
        clockStatisticsVo.setDays(clockDayVos.size());

        long minute = 0;
        //迟到早退时间
        for (ClockDayVo clockDayVo : clockDayVos) {
            if ((ObjectUtil.isNotNull(clockDayVo.getClockOn())&&ObjectUtil.isNotNull(clockDayVo.getClockOff())) &&(clockDayVo.getClockOn()==2||clockDayVo.getClockOff()==4)) {
                RosterWorkerTimeVo rosterWorkerTime = schedulingService.getRosterWorkerTime(workerId, clockDayVo.getDate());
                //迟到
                if (clockDayVo.getClockOn() == 2) {
                    Date timeOn = clockDayVo.getTimeOn();
                    Date startWorkTime = rosterWorkerTime.getStartWorkTime();

                    long sub = Math.abs(timeOn.getTime() - startWorkTime.getTime());
                    if (sub>0) {
                        minute += sub / 1000 / 60 ;
                    }
                }
                //早退
                if (clockDayVo.getClockOff() == 4) {
                    Date timeOff = clockDayVo.getTimeOff();
                    Date endWorkTime = rosterWorkerTime.getEndWorkTime();
                    long sub = Math.abs(endWorkTime.getTime() - timeOff.getTime());
                    if (sub>0) {
                        minute += sub / 1000 / 60 ;
                    }
                }
            }
        }
        clockStatisticsVo.setMinute(minute);

        clockStatisticsVo.setLeaveDays(schedulingService.getLeaveDays(workerId,month));

        return clockStatisticsVo;
    }
}
